/******************************************************************************
* File:             can.c
*
* Author:           iysheng@163.com
* Created:          02/24/22
*                   Can module driver
*****************************************************************************/

#include "sys.h"

__xdata u8 gs_rx_buf[12] = {0x0};
typedef enum {
    CAN_RX_NONE,
	CAN_RX_REMOTE_FRAME,
	CAN_RX_DATA_FRAME,
} can_rx_data_E;
__xdata u8 gs_rx_done = CAN_RX_NONE;

typedef struct {
    u32 baud;
	u8 BRP;
	u8 BTR0;
	u8 BTR1;
} can_baud_map_t;

__idata can_baud_map_t gs_can_baud_maps[3] = {
    {.baud = 125000, 40, 0x17, 0x0A},
    {.baud = 500000, 8, 0x17, 13},
    {.baud = 1000000, 7, 0x17, 0x03},
};

can_baud_map_t * get_can_baud_map(u32 baud)
{
    u8 i = 0;

	//for (; i < sizeof gs_can_baud_maps / sizeof(can_baud_map_t); i++)
	for (; i < 3; i++)
	{
		if (gs_can_baud_maps[i].baud == baud)
		{
			return &gs_can_baud_maps[i];
		}
	}

	return 0;
}

int can_init(u32 baud)
{
	can_baud_map_t *map_ptr;
	/* CAN 管脚映射到 P0.2 P0.3 */
    MUX_SEL |= 0x80;
	CAN_IR = 0x00;
	CAN_ET = 0x00;
	CAN_CR = 0x00;
	gs_rx_done = CAN_RX_NONE;

#if 0
	/* 初始化波特率 */
    sys_write_vp_u32(0xff0060,data);
	/* 初始化波特率 */
    sys_write_vp_u32(0xff0060,data);
#else
	P0MDOUT = 0x04;		//P0.2(CAN_TX)配置为输出
	P0 = 0xFF;		 	//输出高电平
	ADR_H = 0xFF;
	ADR_M = 0x00;
	ADR_L = 0x60;
	ADR_INC = 1;
	RAMMODE = 0x8F;		//写操作
	while(!APP_ACK);
	/* 波特率实际计算公式
	 * f/[( brp+1)*2*(TSeg1+TSeg2+3)]
	 * f 是 206438400
	 * brp 是 0XF00060 的 D3
	 * TSeg1 是 0XF00060 的 D2 的 bit3-0 范围是 0~7, bit7~4 固定为 1
	 * TSeg2 是 0XF00060 的 D1 的 bit3~0 范围是 0~15, bit 7~4 建议为 0
	 * */
	map_ptr = get_can_baud_map(baud);
	if (!map_ptr)
	{
		return -1;
	}
	DATA3 = map_ptr->BRP;
	DATA2 = map_ptr->BTR0;
	DATA1 = map_ptr->BTR1;
	DATA0 = 0x00;//	波特率125K
	APP_EN = 1;
	while(APP_EN);
	DATA3 = 0;
	DATA2 = 0;
	DATA1 = 0;
	DATA0 = 0;	 		//配置验收寄存器ACR,主机只能接收ID第8bit为1的数据，从机验收该位为0
	APP_EN = 1;	
	while(APP_EN);
	DATA3 = 0xFF;
	DATA2 = 0xFF;
	DATA1 = 0xFF;
	DATA0 = 0xFF;	 	//配置AMR,打开ID第0位的验收，主机针对该位进行接收数据
	APP_EN = 1;	
	while(APP_EN);
	RAMMODE = 0;
	/* 使能 CAN 并完成 CAN 配置 */
	CAN_CR = 0xA0;
	while(CAN_CR&0x20);	//执行配置FF0060-FF0062动作
	ECAN = 1;			//打开CAN中断
	EA = 1;				//打开总中断		
#endif
	return 0;
}

/* 默认使用标准帧 */
/* IDE=0 RTR=1 DLC=数据长度 */
#define CAN_STAND_REMOTE_FRAME 0x40
/* IDE=0 RTR=0 DLC=数据长度 */
#define CAN_STAND_DATA_FRAME   0x00

#define MK_CAN_DATA_STD_FRAME(l)    (CAN_STAND_DATA_FRAME | l)
#define MK_CAN_DATA_EXT_FRAME(l)    (CAN_STAND_REMOTE_FRAME | l)

//ID共11位，取前8位表示节点ID
//type表示发送类型，RTR远程帧/数据帧，IDE标准格式/扩展格式固定为0，DLC帧数据长度
//id 表示 ID
void can_tx(u8 type, u16 id, u8 *buffer)
{
	EA = 0;
	ADR_H = 0xFF;
	ADR_M = 0x00;
	ADR_L = 0x64;
	ADR_INC = 1;
	RAMMODE = 0x8F;		//写操作
	while(!APP_ACK);
	DATA3 = type;
	DATA2 = 0;
	DATA1 = 0;
	DATA0 = 0;	 		
	APP_EN = 1;
	while(APP_EN);		//写入RTR,IDE,DLC等数据
	DATA3 = id;
	DATA2 = id >> 8 << 5;
	DATA1 = 0;
	DATA0 = 0;	 		
	APP_EN = 1;
	while(APP_EN);		//写入ID数据
	DATA3 = buffer[0];
	DATA2 = buffer[1];
	DATA1 = buffer[2];
	DATA0 = buffer[3];	 		
	APP_EN = 1;
	while(APP_EN);		//写入发送数据前4字节
	DATA3 = buffer[4];
	DATA2 = buffer[5];
	DATA1 = buffer[6];
	DATA0 = buffer[7];	 		
	APP_EN = 1;
	while(APP_EN);		//写入发送数据后4字节
	EA = 1;
	RAMMODE = 0;
	CAN_CR |= 0x04;		//启动发送			
}

void can_write(u16 id, u8 *buffer, u8 len)
{
    can_tx(MK_CAN_DATA_STD_FRAME(len), id, buffer);
}

void can_isr() __interrupt (9)
{
	EA = 0;
	/* 如果是 remote frame 接收中断
	 * 那么接收的数据只有帧 ID 信息
	 * */
	if((CAN_IR&0xC0) == 0xC0)
	{
		CAN_IR &= 0x3F;	//清空远程帧标记位
		ADR_H = 0xFF;
		ADR_M = 0x00;
		ADR_L = 0x69;
		ADR_INC = 1;
		RAMMODE = 0xAF;		//读操作
		while(!APP_ACK);
		APP_EN = 1;
		while(APP_EN);
		/* 帧 ID */
		gs_rx_buf[0] = DATA3;
		gs_rx_buf[1] = DATA2;
		gs_rx_buf[2] = DATA1;
		gs_rx_buf[3] = DATA0;
		RAMMODE = 0;
		gs_rx_done = CAN_RX_REMOTE_FRAME;
	}
	/* 如果是数据帧接收中断
	 * 说明接收的数据不仅仅有帧 ID ，还有帧数据
	 * */
	else if((CAN_IR&0xC0) == 0x40)
	{
		CAN_IR &= 0xBF;	//清空数据帧标记位
		ADR_H = 0xFF;
		ADR_M = 0x00;
		ADR_L = 0x69;
		ADR_INC = 1;
		RAMMODE = 0xAF;		//读操作
		while(!APP_ACK);
		APP_EN = 1;
		while(APP_EN);
		/* 帧 ID，扩展帧 29 bit 有效，标准帧 11 bit 有效 */
		gs_rx_buf[0] = DATA3;
		gs_rx_buf[1] = DATA2;
		gs_rx_buf[2] = DATA1;
		gs_rx_buf[3] = DATA0;
		APP_EN = 1;
		while(APP_EN);
		/* 保存 8 字节的数据 */
		gs_rx_buf[4] = DATA3;
		gs_rx_buf[5] = DATA2;
		gs_rx_buf[6] = DATA1;
		gs_rx_buf[7] = DATA0;
		APP_EN = 1;
		while(APP_EN);
		gs_rx_buf[8] = DATA3;
		gs_rx_buf[9] = DATA2;
		gs_rx_buf[10] = DATA1;
		gs_rx_buf[11] = DATA0;
		RAMMODE = 0;
		gs_rx_done = CAN_RX_DATA_FRAME;
	}
	if((CAN_IR&0x20) == 0x20)
	{
		CAN_IR &= 0xDF;	//清空发送帧标记位
	}
	if((CAN_IR&0x10) == 0x10)
	{
		CAN_IR &= 0xEF;	//清空接收溢出标记位
	}
	if((CAN_IR&0x08) == 0x08)
	{
		CAN_IR &= 0xF7;	//清空错误标记位
		CAN_ET &= 0xE0;	//清空错误标记	
	}
	if((CAN_IR&0x04) == 0x04)
	{
		CAN_IR &= 0xFB;	//清空仲裁失败标记位
		CAN_CR |= 0x04;	//重新启动发送	
	}
	EA = 1;
}

